import * as THREE from "three";
// import * as d3 from 'd3-geo';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js'
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js'
import { GUI } from 'three/examples/jsm/libs/dat.gui.module.js';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
import store from '../../..//store'

export default class InitThreeJS {
  constructor(options) {
    // super(options);
    this.el = options.el;
    this.width = options.width;
    this.height = options.height;
    this.scene = null;
    this.camera = null;
    this.renderer = null;
    this.controls = null;
    //模型包围盒
    this.modelBox3 = new THREE.Box3();
    this.meshBox3 = new THREE.Box3();
    this.modelObj = null;
    this.modelObjFile = options.modelObj;
    this.modelMtlFile = options.modelMtl;
    this.modelFbx = options.modelFbx;
    this.params = {
      animate: true,
      planeX: { '剖切距离': 15, '反向剖切': false, '剖切面': false },
      planeY: { '剖切距离': 15, '反向剖切': false, '剖切面': false },
      planeZ: { '剖切距离': 15, '反向剖切': false, '剖切面': false }
    }
    this.object = null;
    this.planes = null;
    this.planeObjects = [];
    this.planeHelpers = null;
    this.guiObj = null;
    this.scale = 0.01;
    this.explodeScale = 1.0;
    this.planeWidth = 26;
    this.init()
  }
  init() {
    // 创建场景
    this.createScene()
    // 创建辅助线
    this.createAxesHelper()
    // 创建i相机
    this.createCamera();
    // 创建光照
    this.createLight();
    //  创建渲染器对象
    this.createRenderer()
    this.setControl()
    // 渲染函数
    this.createRender();
  }
  createScene() {
    this.scene = new THREE.Scene();
  }
  createAxesHelper() {
    const axesHelper = new THREE.AxesHelper(300000);
    this.scene.add(axesHelper);
  }
  createLight() {
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
    directionalLight.position.set(400, 200, 300);
    this.scene.add(directionalLight);
    const directionalLight2 = new THREE.DirectionalLight(0xffffff, 1.0);
    directionalLight2.position.set(-400, -200, -300);
    this.scene.add(directionalLight2);
    const ambient = new THREE.AmbientLight(0xffffff, 0.8);
    this.scene.add(ambient);
    this.light = new THREE.PointLight(0xffffff, 1) // 点光源
    this.light.position.set(200, 200, 200)
    this.light.position.multiplyScalar(1.3) // 标量
    this.light.castShadow = true // 告诉平行光需要开启阴影投射
    this.light.shadow.mapSize.width = 500
    this.light.shadow.mapSize.height = 500
    this.scene.add(this.light)
  }
  createCamera() {
    const k = this.height / this.width; //窗口宽高比
    const s = 18; //三维场景显示范围控制系数，系数越大，显示的范围越大
    //创建相机对象
    this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, -1000, 10000);
    // this.camera = new THREE.PerspectiveCamera(100, this.width/this.height, 0.1,10000);
    // this.camera = new THREE.OrthographicCamera(-s, s, s * k, -s * k, 1, 100000);
    this.camera.position.set(6, 6, 6); //设置相机位置
    this.camera.lookAt(this.scene.position);
  }
  createRenderer() {
    this.renderer = new THREE.WebGLRenderer({ antialias: true });
    this.renderer.shadowMap.enabled = true;
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(this.width, this.height);
    this.renderer.setClearColor(0x263238);
    this.renderer.localClippingEnabled = true;
    this.el.appendChild(this.renderer.domElement);
  }
  createRender() {
    for (let i = 0; i < this.planeObjects.length; i++) {

      const plane = this.planes[i];
      const po = this.planeObjects[i];
      plane && plane.coplanarPoint(po.position);
      // po && po.lookAt(
      //   po.position.x - plane.normal.x,
      //   po.position.y - plane.normal.y,
      //   po.position.z - plane.normal.z,
      // );

    }
    // const canvas = this.renderer.domElement;
    // this.camera.aspect = canvas.clientWidth / canvas.clientHeight;
    // this.camera.updateProjectionMatrix();

    this.renderer.setSize(this.width, this.height); //设置渲染区域尺寸
    this.renderer.render(this.scene, this.camera); //执行渲染this.width操作
    requestAnimationFrame(this.createRender.bind(this));

    this.controls.update();
  }
  setControl() {
    this.controls = new OrbitControls(this.camera, this.el);
    this.controls.minDistance = 1;
    this.controls.maxDistance = 30;
    // controls.update();
  }
  initMaterialModel() {
    let that = this
    return new Promise((resolve, reject) => {
      var mtlLoader = new MTLLoader()
      // 加载mtl文件
      mtlLoader.load(that.modelMtlFile, function (material) {
        // 预加载
        material.preload()
        material.side = THREE.DoubleSide;
        var objLoader = new OBJLoader()
        // 设置当前加载的纹理
        objLoader.setMaterials(material)
        objLoader.load(that.modelObjFile, function (object) {
          if (object.children) {
            const bbox = new THREE.Box3().setFromObject(object);
            object.position.set(-(bbox.max.x + bbox.min.x) / 2,
              -(bbox.max.y + bbox.min.y) / 2,
              -(bbox.max.z + bbox.min.z) / 2);
            that.modelObj = object
            that.scene.add(object)
            resolve(object)
          }
        }, that.onProgress, that.onError)
      })

    })

  }
  applyScalar(scalar) {
    const a = this.explodeScale * scalar
    this.modelObj && this.modelObj.traverse(function (value) {
      if (!value.isMesh || !value.worldDir) return;
      //爆炸公式
      value.position.copy(new THREE.Vector3().copy(value.userData.oldPs).add(new THREE.Vector3().copy(value.worldDir).multiplyScalar(a)))
    });
  }
  initModelExplode() {
    //计算模型的中心点坐标，这个为爆炸中心
    const bbox = new THREE.Box3().setFromObject(this.modelObj);
    const modelWorldPs = new THREE.Vector3().addVectors(bbox.max, bbox.min).multiplyScalar(0.5);
    this.modelObj.traverse && this.modelObj.traverse((value) => {
      if (value.isMesh) {
        this.meshBox3.setFromObject(value);
        //获取每个mesh的中心点，爆炸方向为爆炸中心点指向mesh中心点
        var worldPs = new THREE.Vector3().addVectors(this.meshBox3.max, this.meshBox3.min).multiplyScalar(0.5);
        if (isNaN(worldPs.x)) return;
        //计算爆炸方向以及爆炸基础距离
        value.worldDir = new THREE.Vector3().subVectors(worldPs, modelWorldPs);
        //保存初始坐标
        value.userData.oldPs = new THREE.Vector3().copy(value.position);
      }
    });
  }
  // 模型加载进度
  onProgress(xhr) {
    if (xhr.lengthComputable) {
      var percentComplete = xhr.loaded / xhr.total * 100;
      store.commit("app/updataLoadingProgressValue", percentComplete);
    }
  }
  onError(err) {
  }
  // 单模型显隐控制
  singleLayerModelShowHide(name) {
    this.modelObj.children.forEach(item => {
      if (item.name === name) { item.visible = !item.visible }
    })
  }
  // 加载fbx模型
  initFbxModel() {
    // const path = require(this.modelFbx)
    var loader = new FBXLoader();
    return new Promise((resolve, reject) => {
      // loader.load('http://106.12.254.129:39895/data/geologicalModel/韩家湾1.fbx', (object) => {//加载路径fbx文件
      loader.load(this.modelFbx, (object) => {//加载路径fbx文件
        const bbox1 = new THREE.Box3().setFromObject(object);
        const dd = bbox1.max.x - bbox1.min.x
        this.explodeScale = bbox1.max.z - bbox1.min.z;

        this.planeWidth = ((dd * 26) / 1100).toFixed(2)

        // if (bbox1.max.x > 450000) {
        //   this.explodeScale = 100.0;
        //   this.scale = 0.01;
        // } else if (bbox1.max.x > 400000) {
        //   this.explodeScale = 100.0; 
        //   this.scale = 0.03;
        // }
        object.scale.set(this.scale, this.scale, this.scale);
        const bbox = new THREE.Box3().setFromObject(object);
        object.position.set(-(bbox.max.x + bbox.min.x) / 2,
          -(bbox.max.y + bbox.min.y) / 2,
          -(bbox.max.z + bbox.min.z) / 2);
        // object.traverse(function (child) {
        //   if (child.isMesh) {
        //     // child.castShadow = true;
        //     // child.receiveShadow = true;
        //     child.material = new THREE.MeshStandardMaterial({
        //       color: child.material.color,
        //       clippingPlanes: null,
        //       clipShadows: true,
        //       shadowSide: THREE.DoubleSide,
        //     });
        //     child.castShadow = true;
        //     child.renderOrder = 6;
        //   }
        // });


        // this.scene.add(object);//模型
        this.modelObj = object
        this.scene.add(object)
        resolve(object)
      }, this.onProgress);
    })
  }
  // 初始化模型剖切
  initProfileModels() {
    this.planes = [
      new THREE.Plane(new THREE.Vector3(- 1, 0, 0), 15),
      new THREE.Plane(new THREE.Vector3(0, - 1, 0), 15),
      new THREE.Plane(new THREE.Vector3(0, 0, - 1), 15)
    ];
    this.planeHelpers = this.planes.map(p => new THREE.PlaneHelper(p, this.planeWidth, 0xf2f2f2));
    this.planeHelpers.forEach(ph => {
      ph.visible = false;
      this.scene.add(ph);
    })
    this.object = new THREE.Group();
    this.scene.add(this.object)
    this.modelObj.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        child.material.color = child.material.color;
        child.material.clipIntersection = false;
        child.material.clippingPlanes = this.planes
        child.material.clipShadows = this.clipShadows;
        child.material.side = THREE.DoubleSide;
        child.castShadow = true;
        child.renderOrder = 6;
      }
    })
    this.guiObj = new GUI();
    const planeX = this.guiObj.addFolder('X轴');
    planeX.add(this.params.planeX, '剖切面').onChange(v => this.planeHelpers[0].visible = v);
    planeX.add(this.params.planeX, '剖切距离').min(-15).max(15).onChange(d => this.planes[0].constant = d);
    planeX.add(this.params.planeX, '反向剖切').onChange(() => {
      this.planes[0].negate();
      this.params.planeX['剖切距离'] = this.planes[0].constant;
    });
    planeX.open();
    const planeY = this.guiObj.addFolder('Y轴');
    planeY.add(this.params.planeY, '剖切面').onChange(v => this.planeHelpers[1].visible = v);
    planeY.add(this.params.planeY, '剖切距离').min(-15).max(15).onChange(d => this.planes[1].constant = d);
    planeY.add(this.params.planeY, '反向剖切').onChange(() => {
      this.planes[1].negate();
      this.params.planeY['剖切距离'] = this.planes[1].constant;
    });
    planeY.open();
    const planeZ = this.guiObj.addFolder('Z轴');
    planeZ.add(this.params.planeZ, '剖切面').onChange(v => this.planeHelpers[2].visible = v);
    planeZ.add(this.params.planeZ, '剖切距离').min(-15).max(15).onChange(d => this.planes[2].constant = d);
    planeZ.add(this.params.planeZ, '反向剖切').onChange(() => {
      this.planes[2].negate();
      this.params.planeZ['剖切距离'] = this.planes[2].constant;
    });
    planeZ.open()
    let closeArr = document.body.getElementsByClassName("close-bottom") || null;
    if (closeArr.length !== 0) {
      for (let i = 0; i < closeArr.length; i++) {
        //删除元素 元素.parentNode.removeChild(元素);
        if (closeArr[i] != null)
          closeArr[i].style.display = 'none'
      }
    }
  }
  // 模型剖切

  beforeDestroyedPlanes() {
    if (this.planes.length) {
      this.planes[0].constant = 15;
      this.planes[1].constant = 15;
      this.planes[2].constant = 15;
    }
    if (this.planeHelpers.length) {
      this.planeHelpers.forEach(ph => {
        ph.visible = false;
        this.scene.add(ph);
      })
    }
    this.object = null;
    this.planeObjects = [];
    this.guiObj && this.guiObj.destroy()
  }
  // 清除剖切数据
  destroyedPlanes() {
    this.guiObj && this.guiObj.destroy()
  }
  destoryModel() {
    this.modelObj && this.modelObj.remove();
    // this.scene = null;
    // this.camera = null;
    // this.renderer = null;
    // this.controls = null;
    // //模型包围盒
    // this.modelBox3 = null
    // this.meshBox3 = null
    // this.modelObj = null;
    // this.modelObjFile = null
    // this.modelMtlFile = null
    // this.modelFbx = null
  }
  destroyGui() {
    this.guiObj && this.guiObj.destroy()
  }
}
